package com.hzw.saas.service.rss.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.rss.IJournalArticleService;
import com.hzw.saas.api.rss.IJournalService;
import com.hzw.saas.api.rss.IJournalUserActionService;
import com.hzw.saas.api.rss.ILibraryService;
import com.hzw.saas.api.rss.bo.JournalArticleBO;
import com.hzw.saas.api.rss.bo.JournalBO;
import com.hzw.saas.api.rss.bo.JournalUserActionBO;
import com.hzw.saas.api.rss.bo.LibraryBO;
import com.hzw.saas.api.rss.query.JournalArticleFavQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.rss.dao.LibraryElasticRepository;
import com.hzw.saas.service.rss.mapper.JournalArticleMapper;
import com.hzw.saas.service.rss.mapper.LibraryMapper;
import com.hzw.saas.service.rss.model.JournalArticle;
import com.hzw.saas.service.rss.model.Library;
import com.hzw.saas.service.rss.model.LibraryNotice;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 期刊摘要
 * 服务实现类
 * </p>
 *
 * @author sonam
 * @since 2021-06-30
 */
@RequiredArgsConstructor
@Service("journalArticleService")
public class JournalArticleServiceImpl extends ServiceImpl<JournalArticleMapper, JournalArticle> implements IJournalArticleService, IService<JournalArticle> {

    private final LibraryMapper libraryMapper;
    private final JournalArticleMapper journalArticleMapper;
    @Resource(name = "libraryService")
    private ILibraryService libraryService;
    @Resource(name = "journalService")
    private IJournalService journalService;
    @Resource(name = "journalUserActionService")
    private IJournalUserActionService journalUserActionService;
    @Autowired
    private LibraryElasticRepository libraryElasticRepository;

    @Override
    public JournalArticleBO getById(String pid) {
        if (StrUtil.isBlank(pid)) return null;
        return MapperUtil.nf().map(super.getById(pid), JournalArticleBO.class);
    }

    @Override
    public List<JournalArticleBO> query(JournalArticleBO journalArticleBO) {
        if (Objects.isNull(journalArticleBO)) return MapperUtil.nf().mapAsList(this.list(), JournalArticleBO.class);
        JournalArticle journalArticle = MapperUtil.nf().map(journalArticleBO, JournalArticle.class);
        List<JournalArticle> journalSummaries = this.list(Wrappers.<JournalArticle>query().setEntity(journalArticle));
        return MapperUtil.nf().mapAsList(journalSummaries, JournalArticleBO.class);
    }

    @Override
    public void update(JournalArticleBO journalArticleBO) {
        if (journalArticleBO == null) return;
        JournalArticle journalArticle = MapperUtil.nf().map(journalArticleBO, JournalArticle.class);
        this.updateById(journalArticle);
    }

    @Override
    public void delete(JournalArticleBO journalArticleBO) {
        if (journalArticleBO == null) return;
        this.remove(Wrappers.<JournalArticle>query().setEntity(MapperUtil.nf().map(journalArticleBO, JournalArticle.class)));
    }

    @Override
    public void delete(String pid) {
        if (StrUtil.isBlank(pid)) return;
        this.removeById(pid);
    }

    @Override
    @Transactional
    public void collectArticle(JournalArticleFavQuery articleFavQuery) {
        String articleId = articleFavQuery.getArticleId();
        String userId = articleFavQuery.getUserId();
        Integer fav = articleFavQuery.getFav();
        // 查询文章是否存在
        if(this.count(Wrappers.<JournalArticle>lambdaQuery().eq(JournalArticle::getPid, articleId)) == 0) {
            // 直接返回
            return;
        }
        // 构造条件
        JournalUserActionBO journalUserAction = new JournalUserActionBO();
        journalUserAction.setUserId(userId);
        journalUserAction.setArticleId(articleId);
        JournalUserActionBO journalUserActionBO = journalUserActionService.getOne(journalUserAction);
        JournalArticleBO byId = getById(articleFavQuery.getArticleId());
        LibraryNotice map = MapperUtil.nf().map(byId, LibraryNotice.class);
        ArrayList<String> stringArrayList = new ArrayList<>();
        String author = byId.getAuthor();
        String[] split = author.split(",");
        for (int i = 0; i < split.length; i++) {
            stringArrayList.add(split[i]);
        }
        map.setAuthors(stringArrayList);
        map.setCreatorId(articleFavQuery.getUserId());
        map.setDownloadUrl(byId.getLinkUrl());
        map.setDoi(byId.getIdentifier());
        map.setTreeNode(articleFavQuery.getLibraryCatalogId());
        JournalBO byId1 = journalService.getById(byId.getRssId());
        map.setJournalName(byId1.getJournalName());
        if(fav == 1) {
            // 保存文献
            saveArticleToLibrary(articleFavQuery);
            //写入es
            libraryElasticRepository.save(map);
        }

        if(fav == 0) {
            removeArticleToLibrary(articleFavQuery);
            //从es中删除
            libraryElasticRepository.delete(map);
        }

        if (fav == 1 && Objects.isNull(journalUserActionBO)) {
            journalUserAction.setIsFav(1);
            journalUserAction.setFavDate(DateUtil.date());
            journalUserActionService.saveBatch(Collections.singletonList(journalUserAction));
            // 设置用户是否已读状态
            journalUserActionService.changeReadStatus(articleFavQuery.getArticleId(), articleFavQuery.getUserId());
        } else if (fav == 0 || fav == 1) {
            // 更新
            if (Objects.nonNull(journalUserActionBO) && !Objects.equals(journalUserActionBO.getIsFav(), fav)) {
                journalUserActionBO.setIsFav(fav);
                journalUserAction.setFavDate(new Date());
                journalUserAction.setUpdateTime(new Date());
                journalUserActionService.update(journalUserActionBO);
                // 设置用户是否已读状态
                journalUserActionService.changeReadStatus(articleFavQuery.getArticleId(), articleFavQuery.getUserId());
            }
        } else {
            AssertUtil.assertThrow("收藏文章失败，异常的参数", true);
        }
    }

    /**
     * 收藏的文章插入文献表中
     */
    private void saveArticleToLibrary(JournalArticleFavQuery articleFavQuery) {
        String articleId = articleFavQuery.getArticleId();
        if(((LibraryServiceImpl)libraryService).lambdaQuery().eq(Library::getPid, articleId).count() > 0) {
            return;
        }
        JournalArticleBO journalArticleBO = this.getById(articleId);
        JournalBO journalBO = journalService.getById(journalArticleBO.getRssId());
        LibraryBO library = new LibraryBO();
        library.setTitle(journalArticleBO.getTitle());
        library.setDoi(journalArticleBO.getIdentifier());
        library.setPubDate(journalArticleBO.getPubDate());
        library.setDescription(journalArticleBO.getDescription());
        library.setAuthor(journalArticleBO.getAuthor());
        library.setJournalName(journalBO == null ? "" : journalBO.getJournalName());
        library.setLibraryCatalogId(articleFavQuery.getLibraryCatalogId());
        library.setDownloadUrl(journalArticleBO.getLinkUrl());
        library.setType(1); // 收藏
        library.setArticleId(articleId);
        library.setPid(SnowFlakeUtil.nextIdStr());
        libraryService.addArticle(library);
    }

    /**
     * 取消收藏的文章
     */
    private void removeArticleToLibrary(JournalArticleFavQuery articleFavQuery) {
        libraryMapper.removeByArticleId(articleFavQuery.getArticleId(), articleFavQuery.getUserId());
    }

    @Override
    public List<JournalArticleBO> findJournalArticleByIds(List<String> ids) {
        List<JournalArticle> list = this.lambdaQuery().in(JournalArticle::getPid, ids).eq(JournalArticle::getIsDelete, 0).list();
        if (CollectionUtil.isNotEmpty(list)) {
            return MapperUtil.nf().mapAsList(list, JournalArticleBO.class);
        }
        return new ArrayList<>();
    }

    @Override
    public void saveBatch(List<JournalArticleBO> journalArticleBOS) {
        if (CollectionUtil.isEmpty(journalArticleBOS)) return;
        journalArticleBOS.forEach(journalArticleBO -> {
            String pid = journalArticleBO.getPid();
            if (StrUtil.isBlank(pid)) {
                journalArticleBO.setPid(SnowFlakeUtil.nextIdStr());
            }
        });
        this.saveBatch(MapperUtil.nf().mapAsList(journalArticleBOS, JournalArticle.class));
    }

    @Override
    public void updateBatch(List<JournalArticleBO> journalArticleBOS) {
        updateBatchById(MapperUtil.nf().mapAsList(journalArticleBOS, JournalArticle.class));
    }

    @Override
    public List<JournalArticleBO> findJournalArticleByJournalIds(List<String> ids) {
        List<JournalArticle> list = this.lambdaQuery().in(JournalArticle::getRssId, ids)
            .eq(JournalArticle::getIsDelete, 0)
            .orderByDesc(JournalArticle::getCreateTime)
            .list();
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return MapperUtil.nf().mapAsList(list, JournalArticleBO.class);
    }

    @Override
    public IPage<JournalArticleBO> findJournalArticlePage(List<String> ids, PageParam pageParam) {
        if (pageParam == null) {
            pageParam = new PageParam();
        }

        Page<JournalArticle> page = this.page(pageParam.convert(), Wrappers.<JournalArticle>lambdaQuery()
            .in(CollectionUtil.isNotEmpty(ids), JournalArticle::getRssId, ids)
            .orderByDesc(JournalArticle::getPubDate)
            .orderByAsc(JournalArticle::getRssId)
        );
        return PageUtils.convert(page, JournalArticleBO.class);
    }

    @Override
    public IPage<JournalArticleBO> findMyCollection(PageParam pageParam, String userId) {
        if (pageParam == null) {
            pageParam = new PageParam();
        }

        List<JournalUserActionBO> journalUserActions = journalUserActionService.findFavJournalUserActionByUserId(userId);
        if (CollectionUtil.isEmpty(journalUserActions)) {
            return new Page<>();
        }
        HashMap<String, Date> stringStringHashMap = new HashMap<>();
        journalUserActions.forEach(journalUserActionBO -> {
            stringStringHashMap.put(journalUserActionBO.getArticleId(),journalUserActionBO.getUpdateTime());
        });
        List<String> articleIds = journalUserActions.stream().map(JournalUserActionBO::getArticleId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(articleIds)) {
            return new Page<>();
        }
        Page<JournalArticle> page = this.page(pageParam.convert(), Wrappers.<JournalArticle>lambdaQuery()
            .in(JournalArticle::getPid, articleIds)
            .orderByDesc(JournalArticle::getCreateTime));
        List<JournalArticle> records = page.getRecords();
        if (CollectionUtil.isNotEmpty(records)){
            records.forEach(journalArticle -> {
                stringStringHashMap.forEach((s,d)->{
                    if (journalArticle.getPid().equals(s)){
                        journalArticle.setUpdateTime(d);
                    }
                });
            });
        }
        return PageUtils.convert(page, JournalArticleBO.class);
    }

    @Override
    public List<JournalArticleBO> findByIdentifer(List<String> collect) {
        List<JournalArticle> list = this.lambdaQuery().in(JournalArticle::getIdentifier, collect).eq(JournalArticle::getIsDelete, 0)
            .groupBy(JournalArticle::getIdentifier).list();
        if (CollectionUtil.isNotEmpty(list)) {
            return MapperUtil.nt().mapAsList(list, JournalArticleBO.class);
        }
        return Collections.emptyList();
    }

    @Override
    public List<JournalArticleBO> findAll() {
        List<JournalArticle> list = this.lambdaQuery().eq(JournalArticle::getIsDelete, 0).list();
        return MapperUtil.nf().mapAsList(list, JournalArticleBO.class);
    }

    @Override
    public Integer findRepeatDigestCount(String digest) {
        return this.lambdaQuery().eq(JournalArticle::getDigest, digest).count();
    }

    @Override
    public List<JournalArticleBO> findRepeatInsert() {
        List<JournalArticle> list = this.lambdaQuery().eq(JournalArticle::getIsDelete, 0).list();
        List<JournalArticle> list1 = this.lambdaQuery().eq(JournalArticle::getIsDelete, 0).groupBy(JournalArticle::getDigest).list();
        list.removeAll(list1);

        return MapperUtil.nf().mapAsList(list, JournalArticleBO.class);
    }

    @Override
    public void deleteAll() {
        journalArticleMapper.deleteAll();
    }

    @Override
    public List<JournalArticleBO> findByJournalIds(List<String> journalIds) {
        if (CollectionUtil.isNotEmpty(journalIds)) {
            List<JournalArticle> list = this.lambdaQuery().in(JournalArticle::getRssId, journalIds).list();
            return MapperUtil.nf().mapAsList(list, JournalArticleBO.class);
        }
        return null;
    }

    @Override
    public void pictureHandle(String url) {

    }

    @Override
    public List<JournalArticleBO> findByIds(List<String> articleId) {
        if (CollectionUtil.isNotEmpty(articleId)) {
            List<JournalArticle> list = this.lambdaQuery().in(JournalArticle::getPid, articleId).list();
            return MapperUtil.nt().mapAsList(list, JournalArticleBO.class);
        }
        return Collections.emptyList();
    }


}
